﻿using Nop.Core.Domain.Customers;
using Nop.Core.Domain.XJ;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Directory;
using Nop.Services.Logging;
using Nop.Services.Media;
using Nop.Services.Security;
using Nop.Services.XJ;
using Nop.Web.Framework.Security;
using Nop.Web.Models.Home;
using Nop.Web.Models.XJ;
using Senparc.Weixin;
using Senparc.Weixin.Entities.TemplateMessage;
using Senparc.Weixin.MP.Containers;
using Senparc.Weixin.WxOpen.AdvancedAPIs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace Nop.Web.Controllers
{
	public class StockOutController : Controller
	{
		#region Fields
		private readonly static string appId = "wx254193524213940e";
		private readonly static string appSecret = "c020d4fcaceaef04d03194bcf408ba51";
		private readonly IPermissionService _permissionService;
		private readonly IDepartmentService _departmentService;
		private readonly ICustomerService _customerService;
		private readonly ICustomerActivityService _customerActivityService;
		private readonly IFilesService _filesService;
		private readonly IPictureService _pictureService;
		private readonly IMessageService _messageService;
		private readonly ILogger _logger;
		private readonly IGenericAttributeService _genericAttributeService;
		private readonly IXJPlaceService _xjPlaceService;
		private readonly IXJPlaceSignService _xjPlaceSignService;
		private readonly IXJEquipmentCategoryService _xJEquipmentCategoryService;
		private readonly IXJEquipmentService _xJEquipmentService;
		private readonly IXJEquipmentStockService _xJEquipmentStockService;
		private readonly IXJEquipmentStockOutService _xJEquipmentStockOutService;
		private readonly IXJEquipmentStockOutDetailService _xJEquipmentStockOutDetailService;
		private readonly IXJEquipmentStockInService _xJEquipmentStockInService;
		private readonly IXJEquipmentStockInDetailService _xJEquipmentStockInDetailService;
		private readonly IXJEquipmentStockLogService _xJEquipmentStockLogService;
		private readonly IXJInspectionService _xJInspectionService;
		private readonly IXJInspectionPlanService _xJInspectionPlanService;
		private readonly IXJMaintenanceService _xJMaintenanceService;
		private readonly IXJMaintenanceCommentService _xJMaintenanceCommentService;
		#endregion

		#region Ctor
		public StockOutController(
			IPermissionService permissionService,
			IDepartmentService departmentService,
			ICustomerService customerService,
			ICustomerActivityService customerActivityService,
			IFilesService filesService,
			IPictureService pictureService,
			IMessageService messageService,
			ILogger logger,
			IGenericAttributeService genericAttributeService,
			IXJPlaceService xjPlaceService,
			IXJPlaceSignService xjPlaceSignService,
			IXJEquipmentCategoryService xJEquipmentCategoryService,
			IXJEquipmentService xJEquipmentService,
			IXJEquipmentStockService xJEquipmentStockService,
			IXJEquipmentStockOutService xJEquipmentStockOutService,
			IXJEquipmentStockOutDetailService xJEquipmentStockOutDetailService,
			IXJEquipmentStockInService xJEquipmentStockInService,
			IXJEquipmentStockInDetailService xJEquipmentStockInDetailService,
			IXJEquipmentStockLogService xJEquipmentStockLogService,
			IXJInspectionService xJInspectionService,
			IXJInspectionPlanService xJInspectionPlanService,
			IXJMaintenanceService xJMaintenanceService,
			IXJMaintenanceCommentService xJMaintenanceCommentService)
		{
			this._permissionService = permissionService;
			this._departmentService = departmentService;
			this._customerService = customerService;
			this._customerActivityService = customerActivityService;
			this._filesService = filesService;
			this._pictureService = pictureService;
			this._messageService = messageService;
			this._logger = logger;
			this._genericAttributeService = genericAttributeService;
			this._xjPlaceService = xjPlaceService;
			this._xjPlaceSignService = xjPlaceSignService;
			this._xJEquipmentCategoryService = xJEquipmentCategoryService;
			this._xJEquipmentService = xJEquipmentService;
			this._xJEquipmentStockService = xJEquipmentStockService;
			this._xJEquipmentStockOutService = xJEquipmentStockOutService;
			this._xJEquipmentStockOutDetailService = xJEquipmentStockOutDetailService;
			this._xJEquipmentStockInService = xJEquipmentStockInService;
			this._xJEquipmentStockInDetailService = xJEquipmentStockInDetailService;
			this._xJEquipmentStockLogService = xJEquipmentStockLogService;
			this._xJInspectionService = xJInspectionService;
			this._xJInspectionPlanService = xJInspectionPlanService;
			this._xJMaintenanceService = xJMaintenanceService;
			this._xJMaintenanceCommentService = xJMaintenanceCommentService;
		}
		#endregion

		#region Utilities

		#endregion

		[HttpPost]
		[UserValidator]
		public JsonResult List(Customer customer, string sNo = "", string wNo = "", int state = 0, int pageIndex = 0, int pageSize = 10)
		{
			if (null == customer || customer.Deleted)
				return Json(new { result = false, msg = "用户无效" });

			if (customer.IsWarehouseKeeper())
			{
				var outs = _xJEquipmentStockOutService.GetAllStockOuts(
					sNo: sNo,
					wNo: wNo,
					minState: (int)StockOutStateEnum.待审核,
					state: state,
					pageIndex: pageIndex,
					pageSize: pageSize);
				return Json(new
				{
					result = true,
					model = outs.Select(x =>
					{
						x.StateName = Enum.GetName(typeof(StockOutStateEnum), x.State);
						x.CreatedOnString = x.CreatedOn.ToString("yyyy-MM-dd HH:mm:ss");
						return x;
					}),
					outs.TotalPages
				});
			}
			else if (customer.IsDepartmentManager())
			{
				var outs = _xJEquipmentStockOutService.GetAllStockOuts(
					sNo: sNo,
					wNo: wNo,
					departmentId: customer.DepartmentId,
					minState: (int)StockOutStateEnum.待审核,
					state: state,
					pageIndex: pageIndex,
					pageSize: pageSize);
				return Json(new
				{
					result = true,
					model = outs.Select(x =>
					{
						x.StateName = Enum.GetName(typeof(StockOutStateEnum), x.State);
						x.CreatedOnString = x.CreatedOn.ToString("yyyy-MM-dd HH:mm:ss");
						return x;
					}),
					outs.TotalPages
				});
			}
			else
			{
				var outs = _xJEquipmentStockOutService.GetAllStockOuts(
					sNo: sNo,
					wNo: wNo,
					customerId: customer.Id,
					state: state,
					pageIndex: pageIndex,
					pageSize: pageSize);
				return Json(new
				{
					result = true,
					model = outs.Select(x =>
					{
						x.StateName = Enum.GetName(typeof(StockOutStateEnum), x.State);
						x.CreatedOnString = x.CreatedOn.ToString("yyyy-MM-dd HH:mm:ss");
						return x;
					}),
					outs.PageIndex,
					outs.TotalPages
				});
			}
		}

		[HttpPost]
		[UserValidator]
		public JsonResult View(Customer customer, int outId)
		{
			if (null == customer || customer.Deleted)
				return Json(new { result = false, msg = "用户无效" });

			var model = new StockOutModel();
			var stockOut = _xJEquipmentStockOutService.GetXJEquipmentStockOutById(outId);
			if (null != stockOut)
			{
				model.Id = stockOut.Id;
				model.SNo = stockOut.SNo;
				model.State = stockOut.State;
				model.StateName = Enum.GetName(typeof(StockOutStateEnum), stockOut.State);
				model.CustomerId = stockOut.CustomerId;
				model.CustomerName = stockOut.CustomerName;
				model.DepartmentId = stockOut.DepartmentId;
				model.DepartmentName = stockOut.DepartmentName;
				model.CreatedOn = stockOut.CreatedOn.ToString("yyyy-MM-dd HH:mm:ss");
				model.Reviewer = stockOut.Reviewer;
				model.ReviewOn = stockOut.ReviewOn.HasValue ? stockOut.ReviewOn.Value.ToString("yyyy-MM-dd HH:mm:ss") : "";
				model.Keeper = stockOut.Keeper;
				model.KeeperOn = stockOut.KeeperOn.HasValue ? stockOut.KeeperOn.Value.ToString("yyyy-MM-dd HH:mm:ss") : "";
				var details = _xJEquipmentStockOutDetailService.GetAllStockOutDetails(outId);
				if (details.Any())
				{
					foreach (var d in details)
					{
						model.Detail.Add(new StockOutDetailModel
						{
							Id = d.Id,
							EquipmentStockId = d.EquipmentStockId,
							EquipmentId = d.EquipmentId,
							Title = string.Format("{0} {1} {2}", d.Name, d.Manufacturer, d.Specification),
							Label = d.Location,
							Stock = d.Stock,
							Amount = d.Amount,
						});
					}
				}
				var pictures = stockOut.GetAttribute<string>("Pictures");
				if (!string.IsNullOrEmpty(pictures))
				{
					var pictureIds = pictures
						.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
						.Select(x => Convert.ToInt32(x))
						.ToArray();
					foreach (var p in pictureIds)
					{
						model.Pictures.Add(_pictureService.GetPictureUrl(p));
					}
				}

				model.NeedAudit = stockOut.State == (int)StockOutStateEnum.待审核;
				if (model.NeedAudit)
					model.CanAudit = customer.IsDepartmentManager() && customer.DepartmentId == stockOut.DepartmentId;
				model.NeedOut = stockOut.State == (int)StockOutStateEnum.待出库;
				if (model.NeedOut)
					model.CanOut = customer.IsWarehouseKeeper();

				if (stockOut.MaintenanceId > 0)
				{
					var maintenance = _xJMaintenanceService.GetXJMaintenanceById(stockOut.MaintenanceId);
					if (null != maintenance)
					{
						model.WNo = maintenance.SNo;
					}
				}
			}
			return Json(new { resut = true, model });
		}

		[HttpPost]
		[UserValidator]
		public JsonResult Create(Customer customer, int maintenanceId)
		{
			if (null == customer || customer.Deleted)
				return Json(new { result = false, msg = "用户无效" });

			var model = new StockOutModel();
			var maintenance = _xJMaintenanceService.GetXJMaintenanceById(maintenanceId);
			if (null == maintenance)
				return Json(new { result = false, msg = "报修记录无效" });

			model.SNo = _xJEquipmentStockOutService.GenerateNo();
			model.MaintenanceId = maintenance.Id;

			model.PlaceId = maintenance.PlaceId;
			model.PlaceName = _xjPlaceService.GetNameById(maintenance.PlaceId);
			model.CategoryId = maintenance.CategoryId;
			model.CategoryName = maintenance.CategoryName;

			model.State = (int)StockOutStateEnum.保存;
			model.State = (int)MaintenanceStateEnum.待分配;
			model.CustomerId = customer.Id;
			model.CreatedOn = "";

			var categorys = _xJEquipmentCategoryService.GetAllXJEquipmentCategorys().Where(m => m.IsConsumables);
			model.AvailableCategories = categorys.Select(x => { return new SelectItemModel { Id = x.Id, Text = x.Name, PId = x.PId }; }).ToList();
			var places = _xjPlaceService.GetAllXJPlaces();
			model.AvailablePlaces = places.Select(x => { return new SelectItemModel { Id = x.Id, Text = x.Name }; }).ToList();

			return Json(new { resut = true, model });
		}

		[HttpPost]
		[UserValidator]
		public JsonResult Save(Customer customer, StockOutModel model)
		{
			if (null == customer || customer.Deleted)
				return Json(new { result = false, msg = "用户无效" });

			var maintenance = _xJMaintenanceService.GetXJMaintenanceById(model.MaintenanceId);
			if (null == maintenance)
				return Json(new { result = false, msg = "报修记录无效" });

			var stockOut = new XJEquipmentStockOut
			{
				MaintenanceId = maintenance.Id,
				SNo = _xJEquipmentStockOutService.GenerateNo(),
				State = (int)StockOutStateEnum.待审核,
				CustomerId = customer.Id,
				CustomerName = customer.TrueName,
				DepartmentId = customer.DepartmentId,
				DepartmentName = customer.DepartmentName,
				CreatedOn = DateTime.Now,
			};
			_xJEquipmentStockOutService.InsertXJEquipmentStockOut(stockOut);
			if (!string.IsNullOrEmpty(model.SelectedPictureIds))
			{
				_genericAttributeService.SaveAttribute(stockOut, "Pictures", model.SelectedPictureIds);
			}
			if (model.Detail.Any())
			{
				foreach (var d in model.Detail)
				{
					if (d.EquipmentStockId > 0)
					{
						var stock = _xJEquipmentStockService.GetXJEquipmentStockById(d.EquipmentStockId);
						if (null != stock)
						{
							var detail = new XJEquipmentStockOutDetail
							{
								EquipmentStockOutId = stockOut.Id,
								EquipmentStockId = stock.Id,
								EquipmentId = stock.EquipmentId,
								Name = stock.Name,
								Manufacturer = stock.Manufacturer,
								Specification = stock.Specification,
								Location = stock.Location,
								Price = stock.Price,
								Amount = d.Amount,
							};
							_xJEquipmentStockOutDetailService.InsertXJEquipmentStockOutDetail(detail);

							//// 领用申请时只增加冻结数量，不扣减库存；确认出库时再处理库存
							//equipment.Freeze += d.Amount;
							//_xJEquipmentService.UpdateXJEquipment(equipment);
						}
					}
					else
					{
						var equipment = _xJEquipmentService.GetXJEquipmentById(d.EquipmentId);
						if (null != equipment)
						{
							var detail = new XJEquipmentStockOutDetail
							{
								EquipmentStockOutId = stockOut.Id,
								EquipmentStockId = 0,
								EquipmentId = equipment.Id,
								Name = equipment.Name,
								Manufacturer = equipment.Manufacturer,
								Specification = equipment.Specification,
								Location = null,
								Price = equipment.Price,
								Amount = d.Amount,
							};
							_xJEquipmentStockOutDetailService.InsertXJEquipmentStockOutDetail(detail);
						}
					}
				}
			}
			// 同步冻结数量
			_xJEquipmentService.SyncAmount(customer: customer, syncFreeze: true);
			return Json(new { result = true, msg = "领用申请成功", id = stockOut.Id });
		}

		[HttpPost]
		[UserValidator]
		public JsonResult Audit(Customer customer, int outId, bool pass = true)
		{
			if (null == customer || customer.Deleted)
				return Json(new { result = false, msg = "用户无效" });

			var stockOut = _xJEquipmentStockOutService.GetXJEquipmentStockOutById(outId);
			if (stockOut == null || stockOut.Deleted)
				return Json(new { result = false, msg = "记录无效" });
			if (stockOut.State != (int)StockInStateEnum.待审核)
				return Json(new { result = false, msg = "无需审核" });
			if (!customer.IsAdmin() && !(customer.IsDepartmentManager() && customer.DepartmentId == stockOut.DepartmentId))
				return Json(new { result = false, msg = "不能审核" });

			stockOut.Reviewer = customer.TrueName;
			stockOut.ReviewOn = DateTime.Now;
			stockOut.State = pass ? (int)StockOutStateEnum.待出库 : (int)StockOutStateEnum.驳回;
			_xJEquipmentStockOutService.UpdateXJEquipmentStockOut(stockOut);
			//activity log
			_customerActivityService.InsertActivity("AuditStockOut", "审核出库记录：{0}", outId);
			return Json(new { result = true, msg = "审核成功", id = outId });
		}

		[HttpPost]
		[UserValidator]
		public JsonResult Out(Customer customer, int outId, bool pass = true)
		{
			if (null == customer || customer.Deleted)
				return Json(new { result = false, msg = "用户无效" });

			var result = _xJEquipmentStockOutService.Out(outId, pass, customer);
			if (!result.Result)
			{
				return Json(new { result = false, msg = result.Msg });
			}
			//activity log
			_customerActivityService.InsertActivity("AuditStockOut", "审核出库记录：{0}", outId);
			return Json(new { result = true, msg = "出库成功", id = outId });
		}

		/// <summary>
		/// 提醒部门负责人审核或物资部确认发货
		/// </summary>
		/// <param name="id"></param>
		/// <param name="templateId"></param>
		/// <returns></returns>
		public async Task<JsonResult> SubscribeMessage(int id, string templateId = "nQpdDl04GLhjY7EwrF3rk6orDUEI_WcDQ3lp5FUg09k")
		{
			await AccessTokenContainer.RegisterAsync(appId, appSecret);

			var stockOut = _xJEquipmentStockOutService.GetXJEquipmentStockOutById(id);
			if (null == stockOut || stockOut.Deleted)
				return Json(new { success = false, msg = "领用申请无效" });

			string thing1 = "";
			string page = string.Format("pages/stockout/detail?id={0}", stockOut.Id);
			var users = new List<Customer>();
			switch (stockOut.State)
			{
				case (int)StockOutStateEnum.待审核:
					thing1 = "新的出库申请待审核";
					users = _customerService.GetAllCustomers(
						customerRoleId: _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.DepartmentManager).Id,
						departId: stockOut.DepartmentId
						).ToList();
					break;
				case (int)StockOutStateEnum.待出库:
					thing1 = "新的出库申请待出库";
					users = _customerService.GetAllCustomers(
						customerRoleId: _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.WarehouseKeeper).Id
						).ToList();
					break;
				default:
					break;
			}
			if (!users.Any())
				return Json(new { success = false, msg = "无通知用户" });
			try
			{
				var templateMessageData = new TemplateMessageData
				{
					["thing1"] = new TemplateMessageDataValue(thing1),
					["date2"] = new TemplateMessageDataValue(stockOut.CreatedOn.ToString("yyyy年MM月dd日 HH:mm"))
				};

				List<string> openIds = new List<string>();
				string msg = string.Empty;
				bool hasFinished = false;

				foreach (var c in users)
				{
					string openId = c.GetAttribute<string>(SystemCustomerAttributeNames.OpenId);
					if (!string.IsNullOrEmpty(openId))
					{
						openIds.Add(openId);
					}
				}
				foreach (var openId in openIds)
				{
					var result = await MessageApi.SendSubscribeAsync(appId, openId, templateId, templateMessageData, page);
					if (result.errcode == ReturnCode.请求成功)
					{
						hasFinished = true;
					}
					else
					{
						msg = "消息发送失败";
						_logger.Error(result.errmsg);
					}
				}
				if (!hasFinished && !string.IsNullOrEmpty(msg))
					return Json(new { success = false, msg });
				else
				{
					//message.IsFinished = true;
					//_messageService.UpdateMessage(message);
					return Json(new { success = true, msg = "消息已发送" });
				}
			}
			catch (Exception ex)
			{
				_logger.Error(ex.Message);
				return Json(new { success = false, msg = "消息发送失败" });
			}
		}

		/// <summary>
		/// 提醒申请已出库
		/// </summary>
		/// <param name="id"></param>
		/// <param name="templateId"></param>
		/// <returns></returns>
		public async Task<JsonResult> RemindMessage(int id, string templateId = "nQpdDl04GLhjY7EwrF3rk6orDUEI_WcDQ3lp5FUg09k")
		{
			await AccessTokenContainer.RegisterAsync(appId, appSecret);

			var stockOut = _xJEquipmentStockOutService.GetXJEquipmentStockOutById(id);
			if (null == stockOut || stockOut.Deleted)
				return Json(new { success = false, msg = "领用申请无效" });

			string thing1 = string.Format("{0}已出库", stockOut.SNo);
			string page = string.Format("pages/stockout/detail?id={0}", stockOut.Id);
			try
			{
				var templateMessageData = new TemplateMessageData
				{
					["thing1"] = new TemplateMessageDataValue(thing1),
					["date2"] = new TemplateMessageDataValue(stockOut.CreatedOn.ToString("yyyy年MM月dd日 HH:mm"))
				};

				List<string> openIds = new List<string>();
				string msg = string.Empty;
				bool hasFinished = false;

				var customer = _customerService.GetCustomerById(stockOut.CustomerId);
				if (null != customer && !customer.Deleted)
				{
					string openId = customer.GetAttribute<string>(SystemCustomerAttributeNames.OpenId);
					if (!string.IsNullOrEmpty(openId))
					{
						openIds.Add(openId);
					}
				}
				foreach (var openId in openIds)
				{
					var result = await MessageApi.SendSubscribeAsync(appId, openId, templateId, templateMessageData, page);
					if (result.errcode == ReturnCode.请求成功)
					{
						hasFinished = true;
					}
					else
					{
						msg = "消息发送失败";
						_logger.Error(result.errmsg);
					}
				}
				if (!hasFinished && !string.IsNullOrEmpty(msg))
					return Json(new { success = false, msg });
				else
				{
					//message.IsFinished = true;
					//_messageService.UpdateMessage(message);
					return Json(new { success = true, msg = "消息已发送" });
				}
			}
			catch (Exception ex)
			{
				_logger.Error(ex.Message);
				return Json(new { success = false, msg = "消息发送失败" });
			}
		}
	}
}